﻿// -----------------------------------------------------------------------
// <copyright file="KNearestNeighbour.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Pattern_package.Classify_data
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Drawing;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class KNearestNeighbour
    {
        /// <summary>
        /// information for data in each class
        /// </summary>
        Sample_info.InfoOfClass[] classInfo;
        /// <summary>
        /// number of classies in classify
        /// </summary>
        private int NumberOfClass;
        /// <summary>
        /// color for each class
        /// </summary>
        private List<Color> colorOfEachClass;
        /// <summary>
        /// number of correct classify
        /// </summary>
        public int NumberOfCorrectClassify = 0;

        /// <summary>
        /// number of pixel unclassify
        /// </summary>
        public int NumberOfUnClassify = 0;
        private int K;
        private double[,] ValuesToClassfiy;
        public struct Distance
        {
            public double dist;
            public int classNum;
        }
        public void setInfo(Sample_info.InfoOfClass[] classInfo, int NumberOfClass, List<Color> colorOfEachClass, int K, double[,] values)
        {
            this.classInfo = classInfo;
            this.colorOfEachClass = colorOfEachClass;
            this.NumberOfClass = NumberOfClass;
            this.K = K;
            this.ValuesToClassfiy = values;
        }
        /// <summary>
        /// Finds the max.
        /// </summary>
        /// <param name="count">The count.</param>
        /// <returns>the determine class</returns>
        public Color findMax(int[] count, int pi)
        {
            int indexOfmax1, max1, max2;
            List<int> countSort = new List<int>();
            max1 = 0;
            indexOfmax1 = 0;
            for (int i = 0; i < count.Length; i++)
            {
                if (count[i] > max1)
                {
                    max1 = count[i];
                    indexOfmax1 = i;
                }
                countSort.Add(count[i]);
            }
            countSort.RemoveAt(indexOfmax1);
            max2 = countSort.Max();

            if (max1 == max2)
            {
                this.NumberOfUnClassify++;
                return Color.FromArgb(0, 0, 0);
            }
            else
            {
                if (pi >= (indexOfmax1 * this.ValuesToClassfiy.GetLength(0) / this.NumberOfClass) && pi < ((indexOfmax1 * this.ValuesToClassfiy.GetLength(0) / this.NumberOfClass) + (this.ValuesToClassfiy.GetLength(0) / this.NumberOfClass)))
                {
                    this.NumberOfCorrectClassify++;
                }
                return colorOfEachClass[indexOfmax1];
            }
        }
        public Color findKnear(List<Distance> sDist,int pi)
        {
            int[] min = new int[this.NumberOfClass];
            int[] count = new int[this.NumberOfClass];
            count[0] = 0;
            sDist.Sort(delegate(Distance p1, Distance p2) { return p1.dist.CompareTo(p2.dist); });
            for (int i = 0; i < this.NumberOfClass; i++)
            {
                min[i] = sDist[i].classNum;
            }
            for (int i = 0; i < min.Length; i++)
            {
                for (int j = 0; j < this.NumberOfClass; j++)
                {
                    if (min[i] == j)
                    {
                        count[j]++;
                    }
                }
            }
            return findMax(count, pi);

        }
        public Bitmap Classify()
        {
            Bitmap Image = new Bitmap(ValuesToClassfiy.GetLength(0), ValuesToClassfiy.GetLength(1));
            List<Distance> sampleDist = new List<Distance>();
            for (int i = 0; i < ValuesToClassfiy.GetLength(0); i++)
            {
                for (int j = 0; j < ValuesToClassfiy.GetLength(1); j++)
                {
                    sampleDist.Clear();
                    double point = ValuesToClassfiy[i, j];
                    for (int k = 0; k < this.NumberOfClass; k++)
                    {
                        foreach (double s in classInfo[k].data)
                        {
                            Distance d = new Distance();
                            d.classNum = k;
                            d.dist = Math.Abs(point - s);
                            sampleDist.Add(d);
                        }
                    }
                    Color result = findKnear(sampleDist, i);
                    Image.SetPixel(i, j, result);
                }
            }
            return Image;
        }
        
    }
}
